/*
 * table_Constant.c
 *
 *  Created on: 2012/06/29
 *      Author: guanxiaoying
 */
#include "../../parser/coredef.h"
#include "../../parser/cc/cc.h"
typedef struct _CONSTANTINFO
{
	BOOL bFloating;
	U2   size;
	union{
		struct {
			SCHAR  bSigned;
			SCHAR  sign;
			U8	u8Remainder;                        /* Absolute value */
		}integer;
		struct {
			LDOUBLE dbValue;
		}floating;
	}value;
	RBTREE      rbtree;
} CONSTANTINFO, *PCONSTANTINFO;


#define TableSize  (sizeof(CONSTANTINFO ))
#define TableType  PCONSTANTINFO
#define stTable stConstantManager.memoryBlocks
#define maxTable stConstantManager.maxRecordNum
#define  maxNumPerBlk  (stConstantManager.astMaxNum_Block)

static AST gblConstRoot=0;

static TABLEMANAGER stConstantManager = {
//		U4                  usIdx;
		0,
//		PSZ				    con_pszName;    constant
		__FILE__,
//		U2					con_usSize;		constant
		TableSize,
//		U2					block_num;	　　　　　　　Reset clear  際　要
		0,
//		S4					astMaxNum_Block;     １回設定のみ
		0,
//		S4					astTabNum_LastPage; 　　　　Reset clear  際　要
		0,
//		S4					astMaxNum_LastPage;     Reset clear  際　要
		0,
//		U4					ulMaxByte;	　　　　　　　　　　クリアしない
		0,
//		U4					con_minPageSize;　　　　　　　　　　constant
		0
};
static VOID resetListener( U4  procid, U2 index )
{
	if( procid == stConstantManager.u4Idx )
	{
		if( index > 0 && index < MAX_VOLUMN_OF_TABLE )
		{
			stTable[ index-1] = NULL;
		}
	}
}
static TableType core_getTable( AST index )
{
	TableType temp = (TableType)Check_Com( &stConstantManager, resetListener,  index );
	if( temp != NULL ){ return &temp[index%maxNumPerBlk]; } return NULL;
}
static BOOL ClearTable( VOID )
{
	gblConstRoot = 0;
	return Clear_Com( &stConstantManager );
}
static BOOL ResetTable( VOID )
{
	gblConstRoot = 0;
	return Reset_Com( &stConstantManager );
}
static BOOL AllocTable( AST astReqArg )
{
	return AllocTable_Com( &stConstantManager, astReqArg, resetListener );
}

static AST getMaxLineNum( VOID ){
	return maxTable;
}
static AST getLeft( AST index )
{
	TableType pTbl = core_getTable( index );
	if( pTbl == NULL )
	{
		return 0;
	}
	return pTbl->rbtree.astLeftChild;
}
static AST setLeft( AST index, AST value )
{
	TableType pTbl = core_getTable( index );
	if( pTbl == NULL )
	{
		return 0;
	}
	return pTbl->rbtree.astLeftChild = value;
}
static AST getRight( AST index )
{
	TableType pTbl = core_getTable( index );
	if( pTbl == NULL )
	{
		return 0;
	}
	return pTbl->rbtree.astRightChild;
}
static AST setRight( AST index, AST value )
{
	TableType pTbl = core_getTable( index );
	if( pTbl == NULL )
	{
		return 0;
	}
	return pTbl->rbtree.astRightChild = value;
}
static AST getParent( AST index )
{
	TableType pTbl = core_getTable( index );
	if( pTbl == NULL )
	{
		return 0;
	}
	return pTbl->rbtree.astParent;
}
static AST setParent( AST index, AST value )
{
	TableType pTbl = core_getTable( index );
	if( pTbl == NULL )
	{
		return 0;
	}
	return pTbl->rbtree.astParent = value;
}
static AST getIndex( AST index )
{
	return index;
}
static U2 getColor( AST index )
{
	TableType pTbl = core_getTable( index );
	if( pTbl == NULL )
	{
		return 0;
	}
	return pTbl->rbtree.lColor;
}
static U2 setColor( AST index, U2 value )
{
	TableType pTbl = core_getTable( index );
	if( pTbl == NULL )
	{
		return 0;
	}
	return pTbl->rbtree.lColor = value;
}
static ACCESS_RBTREE stAccessRbtree =
{
		AllocTable,
		getMaxLineNum,
		getIndex,
		{
				getLeft,
				setLeft
		},
		{
				getRight,
				setRight
		},
		{
				getParent,
				setParent
		},
		{
				getColor,
				setColor
		}
};

static BOOL isNegative( AST astValue ){
	TableType pTbl = core_getTable( astValue );
	if( pTbl == NULL )
	{
		return FALSE;
	}
	if( pTbl->bFloating ){
		return pTbl->value.floating.dbValue < 0;
	}
	return pTbl->value.integer.sign < 0;
}
static BOOL isSigned( AST astValue ){
	TableType pTbl = core_getTable( astValue );
	if( pTbl == NULL )
	{
		return FALSE;
	}
	if( pTbl->bFloating ){
		return TRUE;
	}
	return pTbl->value.integer.bSigned;
}
static BOOL isFloating( AST astValue ){
	TableType pTbl = core_getTable( astValue );
	if( pTbl == NULL )
	{
		return FALSE;
	}
	if( pTbl->bFloating ){
		return TRUE;
	}
	return FALSE;
}
static U4 getSize( AST astValue ){
	TableType pTbl = core_getTable( astValue );
	if( pTbl == NULL )
	{
		return FALSE;
	}
	return pTbl->size;
}
static S4 comp( AST index, VOID* pastValue ){
	TableType var = (TableType)pastValue;
	TableType pTbl = core_getTable( index );

	if( pTbl == NULL ){
		return RBT_LARGER;
	}
	if( pTbl->bFloating < var->bFloating ){
		return RBT_LARGER;
	}
	if( pTbl->bFloating > var->bFloating  ){
		return RBT_LESS;
	}
	if( pTbl->size < var->size ){
		return RBT_LARGER;
	}
	if( pTbl->size > var->size ){
		return RBT_LESS;
	}
	if( pTbl->bFloating ){
		if( pTbl->value.floating.dbValue < var->value.floating.dbValue ){
			return RBT_LARGER;
		}else if( pTbl->value.floating.dbValue > var->value.floating.dbValue ){
			return RBT_LESS;
		}
	}else{
		if( pTbl->value.integer.bSigned < var->value.integer.bSigned ){
			return RBT_LARGER;
		}else if( pTbl->value.integer.bSigned > var->value.integer.bSigned ){
			return RBT_LESS;
		}
		if( pTbl->value.integer.sign < var->value.integer.sign ){
			return RBT_LARGER;
		}else if( pTbl->value.integer.sign > var->value.integer.sign ){
			return RBT_LESS;
		}
		if( pTbl->value.integer.u8Remainder < var->value.integer.u8Remainder ){
			return RBT_LARGER;
		}else if( pTbl->value.integer.u8Remainder > var->value.integer.u8Remainder ){
			return RBT_LESS;
		}
	}
	return RBT_FOUND;
}
static VOID getValue( AST astValue, CONSTANTINFO*info ){
	AST astType;
	VARVALUE var;
	astType = stValueInfoAccess.type.get( astValue );
	info->bFloating = CcTypeIsFloating( astType );
	info->size = stTypeInfoAccess.size.get( astType );
	if( info->bFloating ){
		info->value.floating.dbValue = CcValueGetFloating(astValue);
	}else{
		var = CcValueGetInteger(astValue);
		info->value.integer.bSigned = CcTypeIsSigned(astType) || CcTypeIsSpecifiedSigned( astType );
		info->value.integer.sign = var.sign;
		info->value.integer.u8Remainder = var.u8Remainder;
	}
}
static VOID setValue( AST astConst, CONSTANTINFO *info ){
	TableType pTbl = core_getTable( astConst );
	if( pTbl == NULL )
	{
		return ;
	}
	pTbl->bFloating = info->bFloating;
	pTbl->size = info->size;
	pTbl->value = info->value;
}
static AST addValue( AST astValue ){
	S4 nCmpResult = 0;
	AST astParent = 0;
	CONSTANTINFO info ;
	AST astConst=0;
	if( astValue == 0 ){
		return 0;
	}
	getValue( astValue, &info );
	nCmpResult = FindData( &stAccessRbtree, gblConstRoot , &info,&astParent, comp );
	if( nCmpResult == RBT_FOUND ){
		return astParent;
	}
	InsertData( &stAccessRbtree, nCmpResult, astParent, &gblConstRoot, &astConst );
	setValue(astConst, &info);
	return astConst;
}
static DOUBLE getFloating( AST astConst );
static VARVALUE getInteger( AST astConst ){
	TableType pTbl = core_getTable( astConst );
	VARVALUE var;
	if( pTbl == NULL )
	{
		var.sign = 1;
		var.u8Remainder = 0;
		var.u4Quotient = 0;
		var.overflow = 0;
		return var;
	}
	if( pTbl->bFloating ){
		LDOUBLE value = getFloating( astConst );
		var.sign = value >= 0.? 1 : -1;
		var.u8Remainder = (U8)value;
		var.u4Quotient = 0;
		var.overflow = TRUE;
	}else{
		var.sign = pTbl->value.integer.sign;
		var.u8Remainder = pTbl->value.integer.u8Remainder;
		var.u4Quotient = 0;
		var.overflow = 0;
	}
	return var;
}
static DOUBLE getFloating( AST astConst ){
	TableType pTbl = core_getTable( astConst );
	DOUBLE var;
	if( pTbl == NULL )
	{
		var = 0.;
		return var;
	}
	if( pTbl->bFloating ){
		var = pTbl->value.floating.dbValue;
	}else{
		VARVALUE value = getInteger( astConst );
		var = value.u8Remainder;
		if( value.sign < 0 ){
			var = -var;
		}
	}
	return var;
}

/*debug,12/10/16,S*/
AST addOuterValue(CONSTANTINFO info){
	S4 nCmpResult = 0;
	AST astParent = 0;
	AST astConst=0;

	nCmpResult = FindData( &stAccessRbtree, gblConstRoot , &info,&astParent, comp );
	if( nCmpResult == RBT_FOUND ){
		return astParent;
	}
	InsertData( &stAccessRbtree, nCmpResult, astParent, &gblConstRoot, &astConst );
	setValue(astConst, &info);
	return astConst;
}
/*debug,12/10/16,E*/

const CONSTANT_ACCESS stConstantAccess={
	ClearTable,
	ResetTable,
	AllocTable,
	getMaxLineNum,
	isNegative,
	isSigned,
	isFloating,
	getSize,
	addValue,
	getInteger,
	getFloating

};
